package com.qipa.netty;

import com.qipa.netty.handler.HealthServerHandler;
import com.qipa.netty.handler.ServerHeartBeatHandler;
import com.qipa.netty.handler.TextWebSocketFrameHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.concurrent.ImmediateEventExecutor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Component
public class ServerInitializer extends ChannelInitializer<SocketChannel> {

    /*是否使用https协议*/
    static final boolean SSL = System.getProperty("ssl") != null;
    //使用DefaultChannelGroup保存所有WebSocket客户端
    private static final ChannelGroup channelGroup = new DefaultChannelGroup(ImmediateEventExecutor.INSTANCE);

    @Autowired
    HealthServerHandler healthServerHandler;

    /**
     * //当新连接accept的时候，这个方法会调用
     *
     * @param ch
     * @throws Exception
     */
    @Override
    public void initChannel(SocketChannel ch) throws Exception {
        // Configure SSL.
        final SslContext sslCtx;
        if (SSL) {
            SelfSignedCertificate ssc = new SelfSignedCertificate();
            sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
        } else {
            sslCtx = null;
        }

        ChannelPipeline p = ch.pipeline();
        if (sslCtx != null) {
            //https处理
            p.addLast(sslCtx.newHandler(ch.alloc()));//addLast在ChannelPipeline的末尾添加ChannelHandler
        }
        p.addLast(new HttpServerCodec());/*HTTP 服务的解码器*/
        p.addLast(new HttpObjectAggregator(2048));/*HTTP 消息的合并处理*/
        //第一个参数：设定IdleStateHandler心跳检测每多少秒进行一次读检测，如果多少秒内ChannelRead()方法未被调用则触发一次userEventTrigger()方法
        //第二个参数：writerIdleTime写空闲超时时间设定，如果write()方法超过writerIdleTime时间未被调用则会触发超时事件调用userEventTrigger()方法；
        //第三个参数：allIdleTime所有类型的空闲超时时间设定，包括读空闲和写空闲；
        p.addLast(new IdleStateHandler(10, 0, 0, TimeUnit.SECONDS));//心跳配置
        p.addLast(new ServerHeartBeatHandler());//处理心跳逻辑处理，把连接都存起来，http连接也会存起来
        p.addLast(healthServerHandler); /*自己写的服务器逻辑处理，如果url后面是ws（websocket），则让下一个去处理*/
        p.addLast(new WebSocketServerProtocolHandler("/ws"));/*处理除TextWebSocketFrame以外的消息事件。所有规定的WebSocket帧类型。接受socket，ws进入聊天室*/
        p.addLast(new TextWebSocketFrameHandler(channelGroup));/*接受socket和websocket，新连接和发送数据都是来这里*/
    }
}
